    ///////////////////////////////////////////////////////////////   
    //   
    // VisualDSP++ 4.0 "Flash Programmer" flash driver for use to   
    // programm the STMicro. M25P64 SPI flash device.   
    // M25P64 -- 64Mbit ( 8M x 8 )   
    // 128 (sectors) x 256 (pages) x 256 (bytes)   
    //    
    ///////////////////////////////////////////////////////////////   
       
    // error enum   
    #include "Errors.h"   
    #include <cdefBF533.h>   
    #include <stdio.h>   
       
    // #defines   
    #define TRUE            0x1   
    #define FALSE           0x0   
    // #define NULL         0x0   
    #define BUFFER_SIZE     0x600   
    #define NUM_SECTORS     128     // number of sectors in the M25P20 flash device   
       
    //Application definitions   
    #define COMMON_SPI_SETTINGS (SPE|MSTR|CPHA|CPOL) //Settings to the SPI_CTL   
    #define TIMOD01 (0x01)      //stes the SPI to work with core instructions   
    #define BAUD_RATE_DIVISOR 200   
       
    //Flash commands   
    #define SPI_WREN            (0x06)  //Set Write Enable Latch   
    #define SPI_WRDI            (0x04)  //Reset Write Enable Latch   
    #define SPI_RDSR            (0x05)  //Read Status Register   
    #define SPI_WRSR            (0x01)  //Write Status Register   
    #define SPI_READ            (0x03)  //Read data from memory   
    #define SPI_PP              (0x02)  //Program Data into memory   
    #define SPI_SE              (0xD8)  //Erase one sector in memory   
    #define SPI_BE              (0xC7)  //Erase all memory   
    #define WIP                 (0x1)   //Check the write in progress bit of the SPI status register   
    #define WEL                 (0x2)   //Check the write enable bit of the SPI status register   
       
    #define TIMEOUT        35000*64   
       

    // structure for flash sector information   
    // for the purpose of erase single sectors of the SPI flash the right sector must be chosen   
    typedef struct _SECTORLOCATION   
    {   
        long lStartOff;   
        long lEndOff;   
           
    }SECTORLOCATION;   
       
       
    // Flash Programmer commands   
    // The VisualDSP++ flash progammer plug-in "Flash Programmer Tool" will send commands   
    // to this driver. These commands will be taken to execute the corresponding C function   
    // The commands are used at the switch case below.   
    typedef enum   
    {   
        NO_COMMAND,     // 0   
        GET_CODES,      // 1   
        RESET,          // 2   
        WRITE,          // 3   
        FILL,           // 4   
        ERASE_ALL,      // 5   
        ERASE_SECT,     // 6   
        READ,           // 7   
        GET_SECTNUM,    // 8   
    }enProgCmds;   
       
       
       
       
    // function prototypes   
    ERROR_CODE SetupForFlash();   
    ERROR_CODE GetCodes();   
    ERROR_CODE Wait_For_Status(char Statusbit);   
    ERROR_CODE Wait_For_WEL();   
    ERROR_CODE ResetFlash();   
    ERROR_CODE EraseFlash();   
    ERROR_CODE EraseBlock( int nBlock );   
    ERROR_CODE FillData( unsigned long ulStart, long lCount, long lStride, int *pnData );   
    ERROR_CODE ReadData(  unsigned long ulStart, long lCount, long lStride, int *pnData  );   
    ERROR_CODE WriteData( unsigned long ulStart, long lCount, long lStride, int *pnData );   
    ERROR_CODE GetSectorNumber( unsigned long ulOffset, int *pnSector );   
    ERROR_CODE WriteFlash ( unsigned long StartAddr, long Count, long Stride, int *pnData, long *pnWriteCount );   
       
    char ReadStatusRegister(void);   
    void Wait_For_SPIF(void);   
    void SetupSPI( const int spi_setting );   
    void SPI_OFF(void);   
    void SendSingleCommand( const int iCommand );   
       
       
    // global data for use with the VisualDSP++ plug-in   
    // The plug-in will modify some AFP variables to control this driver   
    char            *AFP_Title = "ADSP-BF533 STAMP";    // This title will be displayed in the plug-in   
    char            *AFP_Description = "STMicro. M25P64";   // The description will also be displayed in the plug-in   
    enProgCmds      AFP_Command = NO_COMMAND;               // AFP_Command is dedicated to control programm flow   
    int             AFP_ManCode = 0x20;                     // Some devices have Manufacturer codes to autodetect the device   
    int             AFP_DevCode = 0x20;                     // Some devices have device codes to autodetect the device   
    unsigned long   AFP_Offset = 0;                         // AFP_Offset holds the start address to the SPI device   
    int             *AFP_Buffer;                            // The plug-in copies the content of the *.ldr file to the buffer in small portions   
    long            AFP_Size = BUFFER_SIZE;                 // The AFP_Buffer size can be modified to change the size   
    long            AFP_Count = -1;                         // The plug-in copies the number of transfers to be executed to the AFP_Count    
    long            AFP_Stride = -1;                        // For the plug-in Fill function a stride can optionally be inserted   
    int             AFP_NumSectors = NUM_SECTORS;           // The number of SPI sectors are given for sector erase function   
    long            AFP_SectorSize1 = 0x10000;              // The multiplier factor from sector to sector must be given   
    int             AFP_Sector = -1;                        // In case of sector erase the right sector must be chosen and hold in here   
    int             AFP_Error           = 0;                // contains last error encountered   
    bool            AFP_Verify          = FALSE;            // verify writes or not   
    long            AFP_StartOff        = 0x0;              // sector start offset   
    long            AFP_EndOff          = 0x0;              // sector end offset   
    int             AFP_FlashWidth      = 0x8;              // width of the flash device taken   
    int             *AFP_SectorInfo;   

    
    
    SECTORLOCATION SectorInfo[NUM_SECTORS];   
       
       
    // exit flag   
    bool bExit = FALSE;   
       
       
    main()   
    {   
        int i = 0;   
        // by making AFP_Buffer as big as possible the plug-in can send and   
        // receive more data at a time making the data transfer quicker   
        //   
        // by allocating it on the heap the compiler does not create an   
        // initialized array therefore making the driver image smaller   
        // and faster to load   
        //   
        // we have modified the linker description file (LDF) so that the heap   
        // is large enough to store BUFFER_SIZE elements at this point   
           
        // The AFP_Buffer gets filled by the programmer plug-in. The data the plug-in fetches   
        // from the *.ldr file will be stored in the AFP_Buffer byte wise to avoid gaps in the buffer.   
        // The verify command uses the buffer to store the data read from the SPI flash for comparison.   
        // The fill command uses the first address of the buffer to hold the value to be filled.   
           
        // -In case of loading the code to the SPI flash the plug-in will fill the buffer automatically    
        //  so that this driver just has to fetch the data from the buffer and tranfer it to the SPI flash.   
        // -In case of reading the data from the SPI flash (plug-in command "VERIFY") this driver just has    
        //  to fetch the data from the SPI flash and store it in the buffer.   
        AFP_Buffer = (int *)malloc(BUFFER_SIZE);   
       
        // AFP_Buffer will be NULL if we could not allocate storage for the   
        // buffer   
        if ( AFP_Buffer == NULL )   
        {   
            // tell GUI that our buffer was not initialized   
            AFP_Error = BUFFER_IS_NULL;   
        }   
       
       
       
        AFP_SectorInfo = (int*)&SectorInfo[0];   
           
           
        for(i=0;i<NUM_SECTORS;i++){   
       
        // This is the sector table of the STMicro. M25P64 SPI flash device.   
                SectorInfo[i].lStartOff = 0x0000 + i* 0x10000;   
                SectorInfo[i].lEndOff   = 0xFFFF + i* 0x10000;   
        }   
       
        // The while loop below is inserted to give the programmer plug-in control over this driver   
       
        // the plug-in will set a breakpoint at "AFP_BreakReady" forcing the processor to stop.   
        // After the plug-in starts the processor again the function which is selected by AFP_Command will be executed.   
        // After execution the function the processor stops again at the breadpoint at "AFP_BreakReady".   
        // Now the plug-in can place the next command in AFP_Command and start the processor again.    
       
        while ( !bExit )   
        {   
            asm("AFP_BreakReady:");   
                       
            if ( FALSE )   
                asm("jump AFP_BreakReady;");   
       
            // switch on the command   
            switch ( AFP_Command )   
            {   
                // As the plug-in displays manufacturer and device ID this function will fetch it from the SPI flash   
                // The STMicro. M25P64 SPI flash device does not have those IDs so the function is empty.   
                case GET_CODES:   
                    AFP_Error = GetCodes();   
                    break;   
       
                // The plug-in offers to reset the flash. This function will send a "write disable command to the SPI flash.   
                //  Additionally, it checks the status register for the write enable bit "WEL" to be cleared.   
                case RESET:   
                    AFP_Error = ResetFlash();   
                    break;   
       
                // By taking the parameters below the function "WriteData" will program the flash.   
                // AFP_Offset points to the SPI destination address, AFP_Count holds the number of transfers   
                // AFP_Stride holds the address increment and finally AFP_Buffer points to the source buffer.   
                case WRITE:   
                    AFP_Error = WriteData( AFP_Offset, AFP_Count, AFP_Stride, AFP_Buffer );   
                    break;   
       
                // As the programmer plug-in allows to simply fill the SPI flash with any value the    
                // "FILL" function includes the code. The AFP_Offset points to the destination while the AFP_Count    
                // holds the number of locations where the value will be placed. AFP_Stride holds the increment   
                // while AFP_Buffer points to the memory source.   
                case FILL:   
                    AFP_Error = FillData( AFP_Offset, AFP_Count, AFP_Stride, AFP_Buffer );   
                    break;   
       
                // Pushing the "Erase" button on the programmer plug-in the driver executes an erase all command.   
                case ERASE_ALL:   
                    AFP_Error = EraseFlash();   
                    break;   
       
                // Pushing the "Erase Sectors" button on the programmer plug-in makes the driver to take the value from   
                // AFP_Sector and sends the erase sector command followed by the start address of the dedicated sector.   
                // The AFP_Sector gets filled by running the function GET_SECTNUM driven by the plug-in   
                case ERASE_SECT:   
                    AFP_Error = EraseBlock( AFP_Sector );   
                    break;   
       
                // In order to verify the data that has been programmed to the flash the data must been read.   
                // This function will be entered when pushing the Verify button.   
                case READ:   
                    AFP_Error = ReadData( AFP_Offset, AFP_Count, AFP_Stride, AFP_Buffer );   
                    break;   
       
                // Based on the address where to start programming this sector must be erased before.    
                // The function GET_SECTNUM will return the sector number where the start address points to.   
                // The sector number will than be taken to run the EraseBlock function.   
                case GET_SECTNUM:   
                    AFP_Error = GetSectorNumber( AFP_Offset, &AFP_Sector );   
                    break;   
       
                // no command or unknown command do nothing   
                case NO_COMMAND:   
                default:   
                    // set our error   
                    AFP_Error = UNKNOWN_COMMAND;   
                    break;   
            }   
       
            // clear the command   
            AFP_Command = NO_COMMAND;   
        }   
       
        // free the buffer if we were able to allocate one   
        if ( AFP_Buffer )   
            free( AFP_Buffer );   
       
       
        // all done   
        return 0;   
    }   
       
       
       
    //////////////////////////////////////////////////////////////   
    // ERROR_CODE WriteData()   
    //   
    // Write the contents of AFP_Buffer to SPI flash.   
    //   
    // Inputs:  unsigned long ulStart - SPI start address    
    //          long lCount - number of elements write to the SPI   
    //          long lStride - address increment to the SPI   
    //          int *pnData - pointer to data buffer   
    //   
    // This function takes the input parameters and calls the function    
    // WriteFlash which writes the data of AFP_Buffer to the SPI.   
    //   
    // The function WriteFlash will usually be executed multiple times because    
    // the SPI needs a break after a transfer of max. 256 bytes for programming   
    // each following transfer will need recalculated addresses and counts   
    //////////////////////////////////////////////////////////////   
       
    ERROR_CODE WriteData( unsigned long ulStart, long lCount, long lStride, int *pnData )   
    {   
       
        unsigned long ulWStart = ulStart;    
        long lWCount = lCount, lWriteCount;   
        long *pnWriteCount = &lWriteCount;   
        int i;   
           
           
        ERROR_CODE ErrorCode = NO_ERR;   
       
        while (lWCount != 0)   
        {   
            ErrorCode = WriteFlash(ulWStart, lWCount, lStride, pnData, pnWriteCount);   
               
            // After each function call of WriteFlash the counter must be adjusted   
            lWCount -= *pnWriteCount;   
               
            // Also, both address pointers must be recalculated.   
            ulWStart += *pnWriteCount;   
            pnData += *pnWriteCount/4;   
        }   
       
        for(i=0; i<1000; i++)   
        {   
            asm("nop;");   
        }   
       
           
        // return the appropriate error code   
        return ErrorCode;   
           
    }   
       
       
    //////////////////////////////////////////////////////////////   
    // ERROR_CODE FillData()   
    //   
    // Fill flash with a value.   
    //   
    // Inputs:  unsigned long ulStart - offset in flash to start the writes at   
    //          long lCount - number of elements to write, in this case bytes   
    //          long lStride - number of locations to skip between writes   
    //          int *pnData - pointer to data buffer   
    //   
    //////////////////////////////////////////////////////////////   
       
    ERROR_CODE FillData( unsigned long ulStart, long lCount, long lStride, int *pnData )   
    {   
       
           
        unsigned long ulWAddr = ulStart;    
        long lWCount = 1, lWriteCount;   
        long *pnWriteCount = &lWriteCount;   
       
        int i;   
        ERROR_CODE ErrorCode = NO_ERR;  // tells us if there was an error erasing flash   
       
           
        for (i = 0; i < lCount; i++, ulWAddr += lStride)   
        {   
            ErrorCode = WriteFlash(ulWAddr, lWCount, lStride, pnData, pnWriteCount);   
        }   
           
           
        for(i=0; i<1000; i++)   
        {   
            asm("nop;");   
        }   
           
        // return the appropriate error code   
        return ErrorCode;   
           
    }   
       
       
       
    //////////////////////////////////////////////////////////////   
    // ERROR_CODE WriteFlash()   
    //   
    // Write the maximum of 256 bytes to flash.   
    //   
    // Inputs:  unsigned long StartAddr - address to write to   
    //          int iDataSource - pointer to the AFP_Buffer   
    //          long lTransferCount - number of elements to send   
    //////////////////////////////////////////////////////////////   
       
    ERROR_CODE WriteFlash ( unsigned long ulStartAddr, long lTransferCount, long lModify, int *iDataSource, long *lWriteCount )   
    {   
       
        unsigned long ulWAddr;   
        long lWTransferCount = 0;   
        int i;   
        char iData;   
        char *temp = (char *)iDataSource;   
        int dummyread;   
        ERROR_CODE ErrorCode = NO_ERR;  // tells us if there was an error erasing flash   
       
        // First, a Write Enable Command must be sent to the SPI.   
        SendSingleCommand(SPI_WREN);   
           
        // Second, the SPI Status Register will be tested whether the    
        //         Write Enable Bit has been set.    
        ErrorCode = Wait_For_WEL();   
       
        if( POLL_TIMEOUT == ErrorCode )   
            return ErrorCode;   
        else   
       
        // Third, the 24 bit address will be shifted out the SPI MOSI bytewise.   
        SetupSPI( (COMMON_SPI_SETTINGS|TIMOD01) ); // Turns the SPI on   
       
        *pSPI_TDBR = SPI_PP;   
        Wait_For_SPIF();        //wait until the instruction has been sent   
        ulWAddr = (ulStartAddr >> 16);   
        *pSPI_TDBR = ulWAddr;   
        Wait_For_SPIF();        //wait until the instruction has been sent   
        ulWAddr = (ulStartAddr >> 8);   
        *pSPI_TDBR = ulWAddr;   
        Wait_For_SPIF();        //wait until the instruction has been sent   
        ulWAddr = ulStartAddr;   
        *pSPI_TDBR = ulWAddr;   
        Wait_For_SPIF();        //wait until the instruction has been sent   
        dummyread = *pSPI_RDBR; //read dummy to empty the receive register   
       
           
        // Fourth, maximum number of 256 bytes will be taken from the Buffer   
        // and sent to the SPI device.   
        for (i=0; (i < lTransferCount) && (i < 256); i++, lWTransferCount++)   
        {   
            iData = *temp;   
            *pSPI_TDBR = iData;   
            Wait_For_SPIF();        //wait until the instruction has been sent   
       
            ((unsigned char *) temp) ++;   
        }   
               
        SPI_OFF(); // Turns the SPI off   
       
        // Sixth, the SPI Write in Progress Bit must be toggled to ensure the    
        // programming is done before start of next transfer.   
        ErrorCode = Wait_For_Status(WIP);   
           
        if( POLL_TIMEOUT == ErrorCode )   
            return ErrorCode;   
        else   
       
       
           
        *lWriteCount = lWTransferCount;   
           
        return ErrorCode;   
    }   
       
    //////////////////////////////////////////////////////////////   
    // ERROR_CODE ReadData()   
    //   
    // Read a value from flash for verify purpose   
    //   
    // Inputs:  unsigned long ulStart - holds the SPI start address   
    //          int pnData - pointer to store value read from flash   
    //          long lCount - number of elements to read   
    //////////////////////////////////////////////////////////////   
       
    ERROR_CODE ReadData(  unsigned long ulStart, long lCount, long lStride, int *pnData  )   
    {   
       
        unsigned long ShiftValue;   
        char dummyread, *cnData,ReadValue;   
        int i;   
       
        cnData = (char *)pnData; // Pointer cast to be able to increment byte wise   
       
        // Start SPI interface     
        SetupSPI( (COMMON_SPI_SETTINGS|TIMOD01) );   
       
        *pSPI_TDBR = SPI_READ;          // Send the read command to SPI device   
        Wait_For_SPIF();                // Wait until the instruction has been sent   
        ShiftValue = (ulStart >> 16); // Send the highest byte of the 24 bit address at first   
        *pSPI_TDBR = ShiftValue;        // Send the byte to the SPI device   
        Wait_For_SPIF();                // Wait until the instruction has been sent   
        ShiftValue = (ulStart >> 8);  // Send the middle byte of the 24 bit address  at second   
        *pSPI_TDBR = ShiftValue;        // Send the byte to the SPI device   
        Wait_For_SPIF();                // Wait until the instruction has been sent   
        *pSPI_TDBR = ulStart;           // Send the lowest byte of the 24 bit address finally   
        Wait_For_SPIF();                // Wait until the instruction has been sent   
        dummyread = *pSPI_RDBR;         // Read dummy to empty the receive register   
       
        // After the SPI device address has been placed on the MOSI pin the data can be   
        // received on the MISO pin.   
        for (i=0; i<lCount; i++)   
        {   
            *pSPI_TDBR = 0;         //send dummy   
            Wait_For_SPIF();        //wait until the data has been sent   
            ReadValue  = *pSPI_RDBR;    //read    
               
            *cnData = ReadValue;    // Store the value received in the buffer.   
       
            cnData++;               // Increment the pointer of the buffer to store the next value   
        }   
           
        SPI_OFF();                  // Turn off the SPI   
           
       
        for(i=0; i<1000; i++)   
        {   
            asm("nop;");   
        }   
       
        return NO_ERR;   
    }   
       
       
    //////////////////////////////////////////////////////////////   
    // ERROR_CODE EraseFlash()   
    //   
    // Sends an "erase all" command to the flash.   
    //   
    //////////////////////////////////////////////////////////////   
       
    ERROR_CODE EraseFlash()   
    {   
       
        ERROR_CODE ErrorCode = NO_ERR;   
               
        //A write enable instruction must previously have been executed   
        SendSingleCommand(SPI_WREN);   
           
        //The status register will be polled to check the write enable latch "WREN"   
        ErrorCode = Wait_For_WEL();   
       
        if( POLL_TIMEOUT == ErrorCode )   
        {   
            return ErrorCode;   
        }   
        else   
       
        //The bulk erase instruction will erase the whole flash   
        SendSingleCommand(SPI_BE);   
           
        // Erasing the whole flash will take time, so the following bit must be polled.   
        //The status register will be polled to check the write in progress bit "WIP"   
        ErrorCode = Wait_For_Status(WIP);   
           
        return ErrorCode;   
    }   
       
       
    //////////////////////////////////////////////////////////////   
    // ERROR_CODE EraseBlock()   
    //   
    // Sends an "erase block" command to the flash.   
    //   
    //////////////////////////////////////////////////////////////   
       
    ERROR_CODE EraseBlock( int nBlock )   
    {   
        unsigned long ulSectorOff = 0x0, ShiftValue;   
        ERROR_CODE ErrorCode = NO_ERR;     
       
       
        // if the block is invalid just return   
        if ( (nBlock < 0) || (nBlock > AFP_NumSectors) )   
        {   
            ErrorCode = INVALID_BLOCK;  // tells us if there was an error erasing flash   
            return ErrorCode;   
        }   
           
        // figure out the offset of the block in flash   
        if ( (nBlock >= 0) && (nBlock < NUM_SECTORS) )   
        {   
            ulSectorOff = (nBlock * AFP_SectorSize1);   
               
        }   
        else   
        {   
            ErrorCode = INVALID_BLOCK;  // tells us if there was an error erasing flash   
            return ErrorCode;   
        }   
       
        // A write enable instruction must previously have been executed   
        SendSingleCommand(SPI_WREN);   
           
        //The status register will be polled to check the write enable latch "WREN"   
        ErrorCode = Wait_For_WEL();   
           
        if( POLL_TIMEOUT == ErrorCode )   
        {   
            return ErrorCode;   
        }   
        else   
       
           
        //Turn on the SPI to send single commands   
        SetupSPI( (COMMON_SPI_SETTINGS|TIMOD01) );   
       
        // Send the erase block command to the flash followed by the 24 address    
        // to point to the start of a sector.   
        *pSPI_TDBR = SPI_SE;   
        ShiftValue = (ulSectorOff >> 16); // Send the highest byte of the 24 bit address at first   
        Wait_For_SPIF();                    // Wait until the instruction has been sent   
        *pSPI_TDBR = ShiftValue;               
        Wait_For_SPIF();                    // Wait until the instruction has been sent   
        ShiftValue = (ulSectorOff >> 8);  // Send the middle byte of the 24 bit address  at second   
        *pSPI_TDBR = ShiftValue;   
        Wait_For_SPIF();                    // Wait until the instruction has been sent   
        *pSPI_TDBR = ulSectorOff;           // Send the lowest byte of the 24 bit address finally   
        Wait_For_SPIF();                    // Wait until the instruction has been sent   
           
        //Turns off the SPI   
        SPI_OFF();   
        Wait_For_SPIF();                    // Wait until the instruction has been sent   
       
        // Poll the status register to check the Write in Progress bit   
        // Sector erase takes time   
        ErrorCode = Wait_For_Status(WIP);   
       
       
        // block erase should be complete   
        return ErrorCode;   
    }   
       
       
       
       
    //////////////////////////////////////////////////////////////   
    // ERROR_CODE GetCodes()   
    //   
    // Sends an "auto select" command to the flash which will allow   
    // us to get the manufacturer and device codes.   
    //   
    //////////////////////////////////////////////////////////////   
       
    ERROR_CODE GetCodes()   
    {   
           
        // The ST M25P64 does not support manufacturer and device codes.   
        return NO_ERR;   
           
    }   
       
       
    //////////////////////////////////////////////////////////////   
    // ERROR_CODE GetSectorNumber()   
    //   
    // Gets a sector number based on the offset.   
    //   
    // In the flash programmer plug-in a sector can be chosen   
    // and than be erased.   
    //////////////////////////////////////////////////////////////   
       
    ERROR_CODE GetSectorNumber( unsigned long ulOffset, int *pnSector )   
    {   
        int nSector = 0;   
        ERROR_CODE ErrorCode = NO_ERR;   
           
        if(ulOffset > (NUM_SECTORS*0x10000 -1)){   
            ErrorCode = INVALID_SECTOR;   
            return ErrorCode;   
        }   
                   
        nSector = (int)ulOffset/0x10000;   
        *pnSector = nSector;   
           
        // ok   
        return ErrorCode;   
    }   
       
    //////////////////////////////////////////////////////////////   
    // ERROR_CODE ResetFlash()   
    //   
    // This function sends a Write Disable Command to the SPI device   
    // After that it checks the Write Enable Latch.   
    //   
    //////////////////////////////////////////////////////////////   
       
    ERROR_CODE ResetFlash()   
    {   
        char status_register = 0;   
        ERROR_CODE ErrorCode = NO_ERR;     
           
        SendSingleCommand(SPI_WRDI);   
        ErrorCode = Wait_For_Status(WEL);   
       
           
        // reset should be complete   
        return ErrorCode;   
    }   
       
       
    //////////////////////////////////////////////////////////////   
    // int ReadStatusRegister(void)   
    //   
    // Returns the 8-bit value of the status register.   
    // Inputs - none   
    // returns- second location of status_register[2],   
    //         first location is garbage.   
    // Core sends the command   
    //   
    //////////////////////////////////////////////////////////////   
    char ReadStatusRegister(void)   
    {   
        char dummyread, status_register = 0;   
        int n;   
       
        SetupSPI( (COMMON_SPI_SETTINGS|TIMOD01) ); // Turn on the SPI   
       
        *pSPI_TDBR = SPI_RDSR;  //send instruction to read status register   
        Wait_For_SPIF();        //wait until the instruction has been sent   
        dummyread = *pSPI_RDBR; //read dummy to empty the receive register   
        *pSPI_TDBR = 0;         //send dummy to receive the status register   
        Wait_For_SPIF();        //wait until the data has been sent   
        status_register = *pSPI_RDBR;   //read the status register   
           
        SPI_OFF();      // Turn off the SPI   
       
       
        for(n=0; n<1000; n++)   
        {   
            asm("nop;");   
        }   
       
        return status_register;   
    }   
       
    //////////////////////////////////////////////////////////////   
    // void Wait_For_SPIF(void)   
    //   
    // Polls the SPIF (SPI single word transfer complete) bit   
    // of SPISTAT until the transfer is complete.   
    // Inputs - none   
    // returns- none   
    //   
    //////////////////////////////////////////////////////////////   
    void Wait_For_SPIF(void)   
    {   
        int n;   
        unsigned short dummyread;   
           
        for(n=0; n<1000; n++)   
        {   
            asm("nop;");   
        }   
           
        while(1)   
        {   
            unsigned short iTest = *pSPI_STAT;   
            if( (iTest & SPIF) )   
            {   
                break;   
            }   
        }   
        dummyread = *pSPI_RDBR; /*read dummy to empty the receive register */   
    }   
       
       
    //////////////////////////////////////////////////////////////   
    // Wait_For_WEL(void)   
    //   
    // Polls the WEL (Write Enable Latch) bit of the Flash's status   
    // register.   
    // Inputs - none   
    // returns- none   
    //   
    //////////////////////////////////////////////////////////////   
       
    ERROR_CODE Wait_For_WEL(void)   
    {   
        int n, i;   
        char status_register = 0;   
        ERROR_CODE ErrorCode = NO_ERR;  // tells us if there was an error erasing flash   
           
            for(i = 0; i < 35; i++)   
            {   
                status_register = ReadStatusRegister();   
                if( (status_register & WEL) )   
                {   
                    ErrorCode = NO_ERR; // tells us if there was an error erasing flash   
                    break;   
                }   
                   
                for(n=0; n<1000; n++)   
                    asm("nop;");   
                ErrorCode = POLL_TIMEOUT;   // Time out error   
            };   
               
           
        return ErrorCode;   
    }   
    //////////////////////////////////////////////////////////////   
    // Wait_For_Status(void)   
    //   
    // Polls the Status Register of the Flash's status   
    // register until the Flash is finished with its access. Accesses   
    // that are affected by a latency are Page_Program, Sector_Erase,   
    // and Block_Erase.   
    // Inputs - Statusbit   
    // returns- none   
    //   
    //////////////////////////////////////////////////////////////   
       
    ERROR_CODE Wait_For_Status( char Statusbit )   
    {   
        int n, i;   
        char status_register = 0xFF;   
        ERROR_CODE ErrorCode = NO_ERR;  // tells us if there was an error erasing flash   
           
            for(i = 0; i < TIMEOUT; i++)   
            {   
                status_register = ReadStatusRegister();   
                if( !(status_register & Statusbit) )   
                {   
                    ErrorCode = NO_ERR; // tells us if there was an error erasing flash   
                    break;   
                }   
                   
                for(n=0; n<1000; n++)   
                    asm("nop;");   
                ErrorCode = POLL_TIMEOUT;   // Time out error   
            };   
               
           
        return ErrorCode;   
           
    }   
       
    //////////////////////////////////////////////////////////////   
    // void SendSingleCommand( const int iCommand )   
    //   
    // Sends a single command to the SPI flash   
    // inputs - the 8-bit command to send   
    // returns- none   
    //   
    //////////////////////////////////////////////////////////////   
    void SendSingleCommand( const int iCommand )   
    {   
        int n;   
       
        //turns on the SPI in single write mode   
        SetupSPI( (COMMON_SPI_SETTINGS|TIMOD01) );   
       
        //sends the actual command to the SPI TX register   
        *pSPI_TDBR = iCommand;   
       
        //The SPI status register will be polled to check the SPIF bit   
        Wait_For_SPIF();   
       
        //The SPI will be turned off   
        SPI_OFF();   
       
           
        //Pause before continuing   
        for(n=0; n<1000; n++)   
        {   
            asm("nop;");   
        }   
    }   
       
    //////////////////////////////////////////////////////////////   
    // Sets up the SPI for mode specified in spi_setting   
    // Inputs - spi_setting   
    // returns- none   
    //////////////////////////////////////////////////////////////   
    void SetupSPI( const int spi_setting )   
    {   
           
        //sets up the PF2 to be the slave select of the SPI    
        *pSPI_FLG = 0xFB04;   
        *pSPI_BAUD = BAUD_RATE_DIVISOR;   
        *pSPI_CTL = spi_setting;   
       
    }   
       
    //////////////////////////////////////////////////////////////   
    // Turns off the SPI   
    // Inputs - none   
    // returns- none   
    //   
    //////////////////////////////////////////////////////////////   
       
    void SPI_OFF(void)   
    {   
        int i;   
           
        *pSPI_CTL = 0x0400; // disable SPI   
        *pSPI_FLG = 0;   
        *pSPI_BAUD = 0;   
           
        for(i=0; i<1000; i++)   
        {   
            asm("nop;");   
        }   
       
       
    }   


